﻿using GalaSoft.MvvmLight;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
using GalaSoft.MvvmLight.Command;
using System.Collections;
using System;
using System.Collections.Specialized;

namespace DiagramDesigner
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class ContoursViewModel : ViewModelBase
    {
        DataSubItemModel model;

        /// <summary>
        /// Initializes a new instance of the ContoursViewModel class.
        /// </summary>
        public ContoursViewModel(DataSubItemModel model)
        {
            //if (model == null)
            //    throw new NullReferenceException();

            this.model = model;
            ConstructGraphicCollection();
            model.SubItemCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(SubItemCollection_CollectionChanged);
            
            //model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(model_PropertyChanged);
        }        

        void Tool_AddObjectEvent(object sender, AddObjectEventArgs e)
        {
            //todo: make assignment to the model
            GraphicObjects.Add(e.AddedObject);
        }

        void Tool_DeleteObjectEvent(object sender, AddObjectEventArgs e)
        {
            GraphicObjects.Remove(e.AddedObject);
        }

        void model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //TODO: fix bug if someone modifies model and properties become null -fixed but
            //better to avoid ConstructGraphicCollection
            switch (e.PropertyName)
            {
                case DataSubItemModel.AngleLineLeftPropertyName:
                    if (model.AngleLineLeft != null)
                        GraphicObjects.Add(model.AngleLineLeft);
                    else
                        ConstructGraphicCollection();
                    break;

                case DataSubItemModel.SubstratePropertyName:
                    if (model.Substrate != null)
                        GraphicObjects.Add(model.Substrate);
                    else
                        ConstructGraphicCollection();
                    break;
                default:
                    break;
            }
        }

        void ConstructGraphicCollection()
        {
            foreach (PointCollection pc in model.SubItemCollection)
                GraphicObjects.Add(pc);

            if (model.Substrate != null)
                GraphicObjects.Add(model.Substrate);
            if (model.AngleLineLeft != null)
                GraphicObjects.Add(model.AngleLineLeft);
        }

        void SubItemCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //TODO: check correctness 
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Reset:
                    ConstructGraphicCollection();
                    break;
                case NotifyCollectionChangedAction.Add:
                    foreach (object o in e.NewItems)
                        GraphicObjects.Add(o);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (object o in e.OldItems)
                        GraphicObjects.Remove(o);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    foreach (object o in e.OldItems)
                        GraphicObjects.Remove(o);
                    foreach (object o in e.NewItems)
                        GraphicObjects.Add(o);
                    break;
                default:
                    break;
            }
        }
        

        #region Properties
        /// <summary>
        /// The <see cref="SelectedCount" /> property's name.
        /// </summary>
        public const string SelectedCountPropertyName = "SelectedCount";

        private bool _myProperty = false;

        /// <summary>
        /// Sets and gets the SelectedCount property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool SelectedCount
        {
            get
            {
                return _myProperty;
            }

            set
            {
                if (_myProperty == value)
                {
                    return;
                }

                _myProperty = value;
                RaisePropertyChanged(SelectedCountPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="Contours" /> property's name.
        /// </summary>
        public const string ContoursPropertyName = "Contours";

        private ObservableCollection<PointCollection> _contours = new ObservableCollection<PointCollection>();

        /// <summary>
        /// Sets and gets the Contours property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<PointCollection> Contours
        {
            get
            {
                return _contours;
            }

            set
            {
                if (_contours == value)
                {
                    return;
                }

                _contours = value;
                RaisePropertyChanged(ContoursPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="GraphicObjects" /> property's name.
        /// </summary>
        public const string GraphicObjectsPropertyName = "GraphicObjects";

        private ObservableCollection<object> _graphicObjects = new ObservableCollection<object>();

        /// <summary>
        /// Sets and gets the GraphicObjects property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<object> GraphicObjects
        {
            get
            {
                return _graphicObjects;
            }

            private set
            {
                if (_graphicObjects == value)
                {
                    return;
                }

                _graphicObjects = value;
                RaisePropertyChanged(GraphicObjectsPropertyName);
            }
        }
        
        /// <summary>
        /// The <see cref="AngleLineLeft" /> property's name.
        /// </summary>
        public const string AngleLineLeftPropertyName = "AngleLineLeft";

        private LineModel _angleLineLeft = null;

        /// <summary>
        /// Sets and gets the AngleLineLeft property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public LineModel AngleLineLeft
        {
            get
            {
                return model.AngleLineLeft;
            }

            set
            {
                if (model.AngleLineLeft == value)
                {
                    return;
                }

                if (model.AngleLineLeft != null)
                    GraphicObjects.Remove(model.AngleLineLeft);

                if (value != null)
                    GraphicObjects.Add(value);                
                
                model.AngleLineLeft = value;
                RaisePropertyChanged(AngleLineLeftPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="Substrate" /> property's name.
        /// </summary>
        public const string SubstratePropertyName = "Substrate";

        private LineModel _substrate = null;

        /// <summary>
        /// Sets and gets the Substrate property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public LineModel Substrate
        {
            get
            {
                return model.Substrate;
            }

            set
            {
                if (_substrate == value)
                {
                    return;
                }

                if (model.Substrate != null)
                    GraphicObjects.Remove(model.Substrate);

                if (value != null)
                    GraphicObjects.Add(value);     

                model.Substrate = value;
                RaisePropertyChanged(SubstratePropertyName);
            }
        }

        #endregion 


        private ArrayList selectedItems = new ArrayList();
        
        

        #region Commands
        private RelayCommand<IList> _selectionChangedCommand;

        /// <summary>
        /// Gets the SelectionChanged.        
        /// </summary>
        public RelayCommand<IList> SelectionChangedCommand
        {
            get
            {
                return _selectionChangedCommand
                    ?? (_selectionChangedCommand = new RelayCommand<IList>(
                                          items =>
                                          {
                                              selectedItems = new ArrayList(items);
                                          }));
            }
        }

        private RelayCommand _deleteCommand;

        /// <summary>
        /// Gets the DeleteCommand.
        /// </summary>
        public RelayCommand DeleteCommand
        {
            get
            {
                return _deleteCommand ?? (
                    _deleteCommand = new RelayCommand(
                        () =>
                        {

                            foreach (object item in selectedItems)
                            {
                                if (item is PointCollection)
                                {
                                    model.SubItemCollection.Remove((PointCollection)item);
                                }
                                else
                                {
                                    if (item == model.Substrate)
                                    {
                                        GraphicObjects.Remove(item);
                                        model.Substrate = null;
                                    }

                                    if (item == model.AngleLineLeft)
                                    {
                                        GraphicObjects.Remove(item);
                                        model.AngleLineLeft = null;
                                    }
                                }
                            }
                        }));
            }
        }

        private RelayCommand _addCommand;

        /// <summary>
        /// Gets the AddCommand.
        /// </summary>
        public RelayCommand AddCommand
        {
            get
            {
                return _addCommand ?? (
                    _addCommand = new RelayCommand(
                        () =>
                        {
                            PointCollection pc = new PointCollection();
                            Random r = new Random();
                            for (int i = 0; i < 10; ++i)
                            {
                                pc.Add(new Point(i * 10, 150 + r.NextDouble() * 100));
                            }
                            model.SubItemCollection.Add(pc);

                            if (model.Substrate == null)
                            {
                                model.Substrate = new LineModel()
                                {
                                    Pt1 = new Point(100, 100),
                                    Pt2 = new Point(400, 100)
                                };
                            }
                        }
                        ));
            }
        }

        private RelayCommand _checkCommand;
        /// <summary>
        /// Gets the CheckCommand.
        /// </summary>
        public RelayCommand CheckCommand
        {
            get
            {
                return _checkCommand ?? (
                    _checkCommand = new RelayCommand(
                        () =>
                        {
                            if (selectedItems.Count > 0)
                            {
                                MessageBox.Show(model.AngleLineLeft.Pt1.ToString() + "  " + ((LineModel)selectedItems[0]).Pt1.ToString() + "\r\n" + 
                                    model.AngleLineLeft.Pt2.ToString() + "  " + ((LineModel)selectedItems[0]).Pt2.ToString());
                            }
                        }));
            }
        }

        #endregion
    }

}